using System;
using System.Collections.Generic;
using Entity;
using MoonFramework.Scripts.Mono;
using MoonFramework.Scripts.Pool;
using MoonFramework.Template;

namespace MoonFramework.Buff
{
    /// <summary>
    /// 层级状态机
    /// </summary>
    public class BuffFsm
    {
        private Dictionary<string, IBuff> Buffs;
        private Queue<string> CurBuffs;
        public Actor Actor;

        public void Init(Actor actor)
        {
            Actor = actor;
            Buffs = new();
            CurBuffs = new();
            MonoManager.Instance.SendUpdateEvent(OnUpdate);
        }

        public bool CheckBuff(string name) => Buffs.ContainsKey(name);

        public T AllocateBuff<T>(Func<T> createBuff, Action<T> callback = null) where T : class, IBuff
        {
            T buff = ObjPoolManager.Instance.Pop(createBuff, callback);
            AddBuff(buff);
            callback?.Invoke(buff);
            return buff;
        }

        private void OnUpdate()
        {
            while (CurBuffs.Count > 0)
            {
                CurBuffs.TryDequeue(out var buffName);
                if (!Buffs.TryGetValue(buffName, out var buff))
                    continue;
                buff.Enter();
                RemoveBuff(buffName);
            }
        }

        public void AddBuff(IBuff buff)
        {
            var buffName = buff.BuffName;
            if (Buffs.ContainsKey(buffName))
                return;
            Buffs.TryAdd(buffName, buff);
            CurBuffs.Enqueue(buffName);
            buff.Enter();
        }
        
        public void RemoveBuff(string buffName)
        {
            Buffs.Remove(buffName); //考虑禁用类buff，只在buff字典中移除，但不会被队列调用
        }
        
        public void Clear()
        {
            Buffs.Clear();
            CurBuffs.Clear();
        }

        public void Stop()
        {
            Clear();
            MonoManager.Instance.RemoveUpdateEvent(OnUpdate);
        }

        /// <summary>
        /// 彻底销毁所有引用
        /// </summary>
        public void Destroy()
        {
            Stop();
            Actor = null;
            ObjPoolManager.Instance.Push(this);
        }
    }
}